package userDictionaryCreator.v1_0_0;

import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.TreeMap;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;


/************************************************
 * Author: Salandry
 * Version: 1.0.6 - beta
 * Date: 8/20/2012
 * 
 * THIS CODE IS OPEN SOURCE AND FREE FOR ALL. DO NOT BUY OR SELL THIS CODE.
 *
 * This program polls clipboard and allows the user to create a dictionary text file
 * base on clipboard entries. The program will also automatically recall user definitions
 * when their value is taken from clipboard.
 *
 * Still left to do:
 *   Better error reporting
 *   Multi-line translation handling - FIXED..needs testing
 *   More optimized way to deal with translation replacement?
 *   Remember last dictionary?
 * 
 **************************************************/

public class UserDictionaryCreator extends JFrame 
{
	public
	UserDictionaryCreator()
	{
		//initialize variables
		fileMapping = new TreeMap<String, String>();
		
		pFileName = "";
	
		//make new instance of UdcUI, set visible so UI displays
		pUI = new UdcUI(this);
		SwingUtilities.invokeLater(new Runnable()
		{
			public void run()
			{
				pUI.setVisible(true);
			}
		});
		
		//make new instance of clipboard thread, start thread.
		pWatcher = new ClipBoardWatcher(pUI);
		pWatcher.start();
	}
	
	public static void main(String[] args) {
		//main method so it can be called from jar executable
		UserDictionaryCreator udc = new UserDictionaryCreator();

	}

	//trims trailing spaces or line breaks from a string
	public static String removeReturnCharacters(String s)
	{
		s = s.trim();
		if(s.contains("\n"))
			s =s.replaceAll("\n", "\\\\n");
		return s;
	}
	
	//writes a key and value out to dictionary file, or rewrites dictionary file
	public static void appendFile(String key, String value)
	{
		//trim inputs
		String aKey = removeReturnCharacters(key);
		String aValue = removeReturnCharacters(value);
		//using OuputStreamWrtier instead of BufferedWrtier due to unicode encryption necessity
		try
		{
			//if the key doesn't exist, append the value to the end of the file
			if(!fileMapping.containsKey(aKey)) 
			{
				fileMapping.clear();
				readFile();
				
			  Writer fStream = new OutputStreamWriter(
					    new FileOutputStream(pFileName, true), "UTF-8");
			  if(fileMapping.size() != 0)
			  {
				  //System.out.println("NOT EMPTY FILE");
				  fStream.write("\n");
			  }
			  fStream.write(aKey + "\n" + aValue);
			  fileMapping.put(aKey, aValue);
			  fStream.close();
			}
			
			//if the key does exist, the entire dictionary is rewritten
			//i may want a way to optimize this, possibly allow users to write on demand
			else
			{
				fileMapping.put(aKey, aValue);
				Writer fStream = new OutputStreamWriter(
					    new FileOutputStream(pFileName), "UTF-8");
				int i = 0;
				int size = fileMapping.size();
				 for(String s : fileMapping.keySet())
				 {	
					  fStream.write(s + "\n" + fileMapping.get(s));
					  if(i < (size-1))
					  {
						  fStream.write("\n");
					  }
					  i++;
				 }
				  fStream.close();
			}
		}
		catch (Exception e)
		{
			// TODO need better error reporting...grr
			  System.err.println("Error: " + e.getMessage());
		}
			  
	}
	
	//sets file name for class variable, checks for file validity
	public static void setFileName(File file) throws Exception
	{
		if(file.exists() && file.canRead() && file.canWrite() && !file.isDirectory())
			pFileName = file.toString();
		
		// TODO needs better error reporting
		if(pFileName.equals("") || !pFileName.endsWith(".txt"))
			throw new Exception("Invalid File!");
		
		//fileMapping.clear();
		//System.out.println(fileMapping.size());
	}

	//this method reads the dictionary file into a TreeMap so it can be searched quickly
	public static void readFile()
	{	
		 try
		 {
			 BufferedReader br = new BufferedReader 
					 (new InputStreamReader (new FileInputStream (pFileName), "UTF-8"));
			  String strLine;
			  while ((strLine = br.readLine()) != null)   
			  {
				  String strLine2 = br.readLine();
				  fileMapping.put(strLine, strLine2);
			  }
			  br.close();
		 }
		 catch (Exception e)
		 {
			  System.err.println("Error: " + e.getMessage());
		 }	  
	}
	
	//returns the translation for a given clipboard entry
	public String getTranslation(String key)
	{
		return fileMapping.get(key);
	}
	
	//necessary method for using clipboard, purposefully left blank
	public void lostOwnership(Clipboard clipboard, Transferable contents)
	{
		//empty method
	}

	//gets the content from the system clipboard
	public String getClipboardContents()
	{
		Clipboard clip = Toolkit.getDefaultToolkit().getSystemClipboard();
		Transferable t = clip.getContents(null);
		  try {
		        if (t != null && t.isDataFlavorSupported(DataFlavor.stringFlavor)) {
		            String text = (String)t.getTransferData(DataFlavor.stringFlavor);
		            return text;
		        }
		    } catch (UnsupportedFlavorException e) {
		    } catch (IOException e) {
		    }
		    return null;
	}
	
	//shuts down thread
	public class
	ShutdownThread
	  extends Thread
	{
		public void run() 
		{
			pWatcher.interrupt();
			try
			{
				pWatcher.join();
			} catch (InterruptedException e)
			{
				e.printStackTrace();
			}
			System.exit(0);
		}
	}
	//creates new thread to watch clipboard
	private class
	ClipBoardWatcher
	  extends Thread
	{
		public
		ClipBoardWatcher(UdcUI ui) 
		{
			pUI = ui;
		}
		
		@Override
		public void run()
		{
			try {
				//get clip contents, if value is new, checks for translation and updates panels
				while (true) {
					String value = getClipboardContents();
					if (value != null && !value.equals(pOldValue)) {
						pOldValue = value;
						String cleanValue = removeReturnCharacters(value);
						String translation = "";
						if(fileMapping.containsKey(cleanValue))
						{
							translation = fileMapping.get(cleanValue);
						}
						Thread t = pUI.new UpdateLeftPanel(value, translation);
						SwingUtilities.invokeLater(t);
					}
					Thread.sleep(150);
				}
			}
			catch (InterruptedException ex){
				ex.printStackTrace();
			}
		}
		
		private String pOldValue = null;
		private UdcUI pUI;
	}
	private static String pFileName;	
	private static TreeMap<String, String> fileMapping;
	private UdcUI pUI;
	private ClipBoardWatcher pWatcher;
}
